package com.wekri.wechat4j.api.controller;

import com.wekri.wechat4j.api.request.Event;
import com.wekri.wechat4j.api.request.MsgType;
import com.wekri.wechat4j.api.request.WeChatRequest;
import com.wekri.wechat4j.api.response.BaseResponse;
import com.wekri.wechat4j.api.response.TextResponse;
import com.wekri.wechat4j.util.Validator;
import com.wekri.wechat4j.util.XmlUtil;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/**
 * 微信服务，继承此类，用来接收微信服务器通知
 * @author liuweiguo.
 */
public abstract class BaseWechatController {
    protected final Logger logger = LoggerFactory.getLogger(getClass());

    private static final String METHOD_GET = "GET";
    private static final String METHOD_POST = "POST";

    /**
     * 微信监听服务
     *
     * @param request
     * @return
     */
    public String service(HttpServletRequest request) {
        if (METHOD_POST.equals(request.getMethod())) {
            return doPost(request);
        } else if (METHOD_GET.equals(request.getMethod())) {
            return toGet(request);
        } else {
            logger.warn("weChat service unsupported method:{}", request.getMethod());
            return "";
        }
    }

    private String doPost(HttpServletRequest request) {
        String postDataStr = null;
        try {
            byte[] byteArr = IOUtils.toByteArray(request.getInputStream());
            if (byteArr.length > 0) {
                postDataStr = new String(byteArr, "utf-8");
            }
        } catch (IOException e) {
            logger.error("post data failed!", e);
        }

        logger.info("parse post data:{}", postDataStr);

        // 消息分发处理
        String xmlStr = XmlUtil.toXmlStr(dispatchMessage(XmlUtil.parseObject(postDataStr, WeChatRequest.class)));
        logger.info("返回：{}", xmlStr);
        return xmlStr;
    }

    private String toGet(HttpServletRequest request) {
        String signature = request.getParameter("signature");
        String timestamp = request.getParameter("timestamp");
        String nonce = request.getParameter("nonce");
        String echoStr = request.getParameter("echostr");
        String token = getToken();
        logger.info("设置微信服务器signature:{}, timestamp:{}, nonce:{}, echoStr:{}",
                signature, timestamp, nonce, echoStr);

        Validator validator = new Validator(signature, timestamp, nonce, token);
        if (!validator.checkSignature()) {
            return "error";
        }
        if (StringUtils.isNotEmpty(echoStr)) {
            return echoStr;
        }
        return null;
    }

    /**
     *
     */
    private BaseResponse dispatchMessage(WeChatRequest wechatRequest){
        logger.info("distributeMessage start");
        if (StringUtils.isEmpty(wechatRequest.getMsgType())) {
            logger.warn("msgType is null");
        }
        MsgType msgType = MsgType.valueOf(wechatRequest.getMsgType());
        logger.info("msgType is {}", msgType.name());
        switch (msgType) {
            case event:
                return dispatchEvent(wechatRequest);
            case text:
                return onText(wechatRequest);
            case image:
                return onImage(wechatRequest);
            case voice:
                return onVoice(wechatRequest);
            case video:
                onVideo();
                break;
            case shortvideo:
                onShortVideo();
                break;
            case location:
                onLocation();
                break;
            case link:
                onLink();
                break;
            case miniprogrampage:
                onMiniProgramPage(wechatRequest);
            default:
                onUnknown();
                break;
        }
        return null;
    }

    /**
     * event事件分发
     */
    private BaseResponse dispatchEvent(WeChatRequest wechatRequest) {
        Event event = Event.valueOf(wechatRequest.getEvent());
        logger.info("dispatch event,event is: {}", event.name());
        switch (event) {
            case subscribe:
                return subscribe(wechatRequest);
            case unsubscribe:
                return unSubscribe(wechatRequest);
            case SCAN:
                scan(wechatRequest);
                break;
            case LOCATION:
                location(wechatRequest);
                break;
            case TEMPLATESENDJOBFINISH:
                return templateMsgCallback(wechatRequest);
            case CLICK:
                return click(wechatRequest);
            case VIEW:
                view();
                break;
            case scancode_push:
                return scanCodePush(wechatRequest);
            case scancode_waitmsg:
                return scanCodeWaitMsg(wechatRequest);
            case pic_sysphoto:
                picSysPhoto();
                break;
            case pic_photo_or_album:
                picPhotoOrAlbum();
                break;
            case pic_weixin:
                picWeixin();
                break;
            case location_select:
                locationSelect();
                break;
            default:
                unknownEvent();
                break;
        }
        return null;
    }

    /**
     * 关注公众号事件
     * @param wechatRequest
     * @return
     */
    protected abstract BaseResponse subscribe(WeChatRequest wechatRequest);

    /**
     * 取消关注公众号事件
     * @param wechatRequest
     * @return
     */
    protected abstract BaseResponse unSubscribe(WeChatRequest wechatRequest);

    /**
     * 扫描二维码
     * @return
     */
    protected abstract void scan(WeChatRequest wechatRequest);

    /**
     * 上报地理位置事件
     * @return
     */
    protected abstract String location(WeChatRequest wechatRequest);

    /**
     * 微信模板消息推送结果回调
     * @return
     */
    protected abstract BaseResponse templateMsgCallback(WeChatRequest wechatRequest);

    /**
     * 自定义菜单点击事件
     *
     * @param wechatRequest
     * @return
     */
    protected abstract BaseResponse click(WeChatRequest wechatRequest);

    protected abstract void view();

    /**
     * 扫码推事件用户点击按钮后，微信客户端将调起扫一扫工具，完成扫码操作后显示扫描结果（如果是URL，将进入URL），且会将扫码的结果传给开发者，开发者可以下发消息
     *
     * @param wechatRequest
     * @return
     */
    protected abstract BaseResponse scanCodePush(WeChatRequest wechatRequest);

    /**
     * 扫码推事件且弹出“消息接收中”提示框用户点击按钮后，微信客户端将调起扫一扫工具，完成扫码操作后，将扫码的结果传给开发者，同时收起扫一扫工具，然后弹出“消息接收中”提示框，随后可能会收到开发者下发的消息。
     *
     * @param wechatRequest
     * @return
     */
    protected abstract BaseResponse scanCodeWaitMsg(WeChatRequest wechatRequest);

    protected abstract void picSysPhoto();

    protected abstract void picPhotoOrAlbum();

    protected abstract void picWeixin();

    protected abstract void locationSelect();

    protected abstract void unknownEvent();


    protected abstract BaseResponse onText(WeChatRequest request);

    protected abstract BaseResponse onImage(WeChatRequest request);

    protected abstract BaseResponse onVoice(WeChatRequest request);

    protected abstract BaseResponse onMiniProgramPage(WeChatRequest request);

    protected abstract void onVideo();

    protected abstract void onShortVideo();

    protected abstract void onLocation();

    protected abstract void onLink();

    protected abstract void onUnknown();

    /**
     * 微信公众号后台-服务器配置中的令牌(Token)
     * @return
     */
    protected abstract String getToken();

    public TextResponse buildTextResponse(WeChatRequest wechatRequest, String content) {
        TextResponse textResponse = new TextResponse();
        textResponse.setFromUserName(wechatRequest.getToUserName());
        textResponse.setToUserName(wechatRequest.getFromUserName());
        textResponse.setCreateTime(System.currentTimeMillis());
        textResponse.setMsgType(MsgType.text.name());
        textResponse.setContent(content);
        return textResponse;
    }
}
